package services;

import java.awt.Color;
import java.util.List;

import model.Part;

public class ScoreService {
	
	public static Part getHighestScorePart() {
		ScoreService.initAvailablePartsScores();
		Part part = ScoreService.getMaxScorePart();
		
		return part;
	}
	
	private static Part getMaxScorePart() {
		Part maxScorePart = null;
		for (Part tmpPart : PartService.getNotChosenBoardParts()) {
			if (maxScorePart == null || (tmpPart.getScore() > maxScorePart.getScore())) {
				maxScorePart = tmpPart;
			}
		}
		
		return maxScorePart;
	}
	
	private static void initAvailablePartsScores() {
		for (Part tmpPart : PartService.getNotChosenBoardParts()) {
			float score = 0;
			Color currentColor = StateService.currentTurnColor();
			
			// temporary coloring the not chosen part
			tmpPart.setColor(currentColor);
			
			score += ScoreService.winningScore(tmpPart) + 10000;
			score += ScoreService.losingScore(tmpPart) * 7000;
			score += ScoreService.surroundingComputerPartScore(tmpPart) * 6000;
			score += (ScoreService.leavingOpponentNeighborWithOneNotChosenNeighborScore(tmpPart) > 0) ? 5000 : -1;
			score += ScoreService.surroundedPartScore(tmpPart) * 50;
			score += ScoreService.increaseOpponentNeighborNumbersScore(tmpPart);
			score += ScoreService.notChosenNeighborsAmmountScore(tmpPart);
			score += ScoreService.increaseComputerNeighborNumbersScore(tmpPart);
			score += Math.random();
			
			tmpPart.setScore(score);
			
			// coloring the not chosen part back to CYAN
			tmpPart.setColor(Color.CYAN);
		}
	}
	
	// Good steps methods
	
	public static int winningScore(Part part) {
		boolean winningStep = 
				PartService.isOneOfOpponentNeighborsSurrounded(part);
		return winningStep ? 1 : 0;
	}
	
	/**
	 * Each of the opponent neighbors will have one more 
	 * surrounding part in case this part is chosen
	 * @param tmpPart
	 * @return the number of opponent neighbors
	 */
	public static int increaseOpponentNeighborNumbersScore(Part tmpPart) {
		return PartService.getSpecificColorNeighbors(tmpPart, StepService.getOpponentTurn(tmpPart.getColor())).size();
	}

	/**
	 * The higher number of not chosen neighbors decreases the risk
	 * to the computer part from being surrounded
	 * @param part
	 * @return the number of the not chosen neighbors
	 */
	public static int notChosenNeighborsAmmountScore(Part part) {
		return PartService.getNotChosenNeighbors(part).size();
	}
	
	/**
	 * if the chosen part is already surrounded then it can't
	 * cause losing afterwards
	 * @param part
	 * @return 1 if surrounded
	 */
	public static int surroundedPartScore(Part part) {
		return PartService.isSurrounded(part) ? 1 : 0;
	}
	
	/**
	 * if choosing this part will cause surrounding any other of the 
	 * computer parts it will prevent losing to the player
	 * @param part
	 * @return
	 */
	public static int surroundingComputerPartScore(Part part) {
		return PartService.isOneOfPartColorNeighborsSurrounded(part) ? 1 : 0;
	}
	
	// Bad steps Methods
	
	/**
	 * 
	 * @param part
	 * @return
	 */
	private static int losingScore(Part part) {
		List<Part> partColorNeighborList =
				PartService.getSpecificColorNeighbors(part, part.getColor());
		
		for (Part tmpPart : partColorNeighborList) {
			if (PartService.getNotChosenNeighbors(tmpPart).size() == 1) {
				return -1;
			}
		}
		
		if (PartService.getNotChosenNeighbors(part).size() == 1) {
			return -1;
		}
		
		return 0;
	}
	
	/**
	 * Each of the computer neighbors will have one more 
	 * surrounding part in case this part is chosen
	 * @param part
	 * @return -1 * the number of the computer neighbors
	 */
	public static int increaseComputerNeighborNumbersScore(Part part) {
		return -1 * PartService.getSpecificColorNeighbors(part, part.getColor()).size();
	}
	
	/**
	 * if choosing this part will cause the opponent neighbor to 
	 * have one not chosen neighbor, it is a bad step because the opponent
	 * can choose this part later and prevent computer from winning
	 * but.. if choosing this part will cause more than one situation
	 * like this, it will ensure winning by the computer in the turn maximum.
	 * @param part
	 * @return
	 */
	public static int leavingOpponentNeighborWithOneNotChosenNeighborScore(Part part) {
		int numberOfOpponentNrighbotWithOneNotChosenNeighbor = 0;
		List<Part> opponentNeighborList = PartService.getSpecificColorNeighbors(part,
				StepService.getOpponentTurn(part.getColor()));
		
		for (Part tmpPart : opponentNeighborList) {
			boolean oneNotChosenNeighbor =
					PartService.getNotChosenNeighbors(tmpPart).size() == 1;
			
			if (oneNotChosenNeighbor) {
				numberOfOpponentNrighbotWithOneNotChosenNeighbor++;
			}
		}
		
		return (numberOfOpponentNrighbotWithOneNotChosenNeighbor == 1) ? 
				-1 : numberOfOpponentNrighbotWithOneNotChosenNeighbor;
	}

}
